/**
 * 
 */
package info.niwota.profile.web;

import info.niwota.commons.io.Files;
import info.niwota.commons.web.ContentHelper;
import info.niwota.profile.Debug;
import info.niwota.profile.Preferences;
import info.niwota.profile.Utils;

import java.io.File;
import java.io.FileInputStream;
import java.io.FilenameFilter;

import org.json.JSONObject;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.net.Uri.Builder;
import android.text.TextUtils;
import android.util.Log;

/**
 * Peer profile is stored at the following locations:
 * 
 * [cache]/peer/json/<peer> 
 * [cache]/peer/profile/<peer>/size (thumbnail,
 * vignette)
 * 
 * @author qiangli
 * 
 */
public class Helper {
	private static final String JSONP_LOAD_PROFILE = "/content/info.niwota.profile/jsonp/profile/"
			+ ProfileObject.GET_PROFILE;

	private static final String BIN_PHOTO = "/content/info.niwota.profile/bin/photo";

	private static final String TAG = "Helper";

	private static final String PEER_JSON_PATH = "/peer/json/";

	private static final String PEER_PROFILE_PATH = "/peer/profile/";

	private static final String MY_PROFILE_PATH = "/profile/";

	public static File[] listVisited(Context ctx) {
		File cacheDir = Files.getCacheDir(ctx);
		File cache = new File(cacheDir, PEER_JSON_PATH);
		return cache.listFiles(new FilenameFilter() {
			public boolean accept(File dir, String filename) {
				return filename.indexOf("@") > 0;
			}
		});
	}

	public static JSONObject getPeerProfile(Context ctx, String peer,
			boolean nocache) throws Exception {
		File cachefile = getPeerJSONFile(ctx, peer);
		
		try {
			if (!nocache && cachefile.exists()) {
				return ContentHelper.readObject(cachefile);
			}
		} catch (Exception e) {
			cachefile.delete();
		}
		String path = JSONP_LOAD_PROFILE + "?format=text/plain&peer=" + peer;
		final Uri cu = ContentHelper.buildUri(path);
		if (Debug.DEBUG) {
			Log.d(TAG, "getProfile peer: " + peer + " path: " + path + " cu: "
					+ cu);
		}
		String s = ContentHelper.getContent(ctx, cu);
		if (s.startsWith("STATUS-5") || s.startsWith("STATUS-4")) {
			throw new Exception(errorText(s));
		}
		JSONObject json = new JSONObject(s);
		json.put("peer", peer);
		ContentHelper.saveObject(json, cachefile);
		cachefile.setLastModified(System.currentTimeMillis());

		return json;
	}

	private static File getPeerJSONFile(Context ctx, String peer) {
		final String cachepath = PEER_JSON_PATH + peer;

		File cacheDir = Files.getCacheDir(ctx);
		File cachefile = new File(cacheDir, cachepath);
		
		return cachefile;
	}

	private static String errorText(String error) {
		try {
			int idx = error.indexOf(":");
			return error.substring(idx + 1).trim();
		} catch (Exception e) {
		}
		return error;
	}

	public static File getProfileContextFolder(Context ctx) {
		return ctx.getDir("profile", Context.MODE_PRIVATE);
	}

	public static Bitmap loadPeerPhoto(Context ctx, String peer, boolean thumb,
			boolean nocache) throws Exception {
		if (Debug.DEBUG) {
			Log.d(TAG, "loadPeerPhoto thumb: " + thumb);
		}

		Bitmap bm = null;
		File file = getPeerPhotoFile(ctx, peer, thumb, nocache);

		if (Debug.DEBUG) {
			Log.d(TAG, "loadPeerPhoto file: " + file);
		}

		FileInputStream is = null;
		try {
			is = new FileInputStream(file);
			bm = BitmapFactory.decodeStream(is);
		} finally {
			if (is != null) {
				is.close();
			}
		}
		return bm;
	}

	public static Bitmap loadCachedPeerThumb(Context ctx, String peer)
			throws Exception {
		Bitmap bm = null;
		File file = getCachedPeerThumbFile(ctx, peer);

		if (Debug.DEBUG) {
			Log.d(TAG, "loadCachedPeerThumb: " + file);
		}
		if (!file.exists()) {
			return null;
		}
		FileInputStream is = null;
		try {
			is = new FileInputStream(file);
			bm = BitmapFactory.decodeStream(is);
		} finally {
			if (is != null) {
				is.close();
			}
		}
		return bm;
	}

	public static File getCachedPeerThumbFile(Context ctx, String peer) {
		File cacheDir = Files.getCacheDir(ctx);
		File thumbfile = new File(cacheDir, PEER_PROFILE_PATH + peer
				+ "/thumbnail");
		return thumbfile;
	}

	public static File getCachedPeerPhotoFile(Context ctx, String peer) {
		File cacheDir = Files.getCacheDir(ctx);
		File thumbfile = new File(cacheDir, PEER_PROFILE_PATH + peer
				+ "/vignette");
		return thumbfile;
	}

	public static File getPeerPhotoFile(Context ctx, String peer,
			boolean thumb, boolean nocache) throws Exception {
		//
		final String size = thumb ? "thumbnail" : "vignette";

		final File cachefile = (thumb ? getCachedPeerThumbFile(ctx, peer)
				: getCachedPeerPhotoFile(ctx, peer));

		if (!nocache && cachefile.exists()) {
			if (Debug.DEBUG) {
				Log.d(TAG, "returning cached thumbnail: " + cachefile);
			}
			return cachefile;
		}

		// otherwise get it
		Uri base = Uri.parse(BIN_PHOTO);
		Builder b = base.buildUpon();
		b.appendQueryParameter("peer", peer);
		b.appendQueryParameter("format", "text/plain");
		b.appendQueryParameter("size", size);
		b.appendQueryParameter("cache", "false");
		b.appendQueryParameter("data", "true");

		String path = b.toString();
		final Uri cu = ContentHelper.buildUri(path);

		if (Debug.DEBUG) {
			Log.d(TAG, "getPhoto downloading... peer: " + peer + " path: "
					+ path + " cu: " + cu);
		}
		// download
		try {
			cachefile.getParentFile().mkdirs();
			ContentHelper.saveContent(ctx, cu, cachefile);
		} catch (Exception e) {

			throw e;
		}
		if (Debug.DEBUG) {
			Log.d(TAG, "cached: " + cachefile);
		}
		cachefile.setLastModified(System.currentTimeMillis());

		return cachefile;
	}

	public static void clearCache() {
		//
	}

	public static File getMyPhoto(Context ctx, boolean thumb) throws Exception {
		String prefix = null;
		int width = 0;
		int height = 0;

		if (thumb) {
			prefix = "thumb";
			width = 96;
			height = 96;
		} else {
			prefix = "vignette";
			width = 480;
			height = 320;
		}
		//
		final File image = getMyPhotoOriginal(ctx);
		if (image == null) {
			return null;
		}
		File file = null;
		if (thumb) {
			file = getMyPhotoThumbnail(ctx);
		} else {
			final File newImage = getCacheFile(ctx, MY_PROFILE_PATH + prefix
					+ ".png");

			if (!newImage.exists()) {
				newImage.getParentFile().mkdirs();
			}
			//
			if (!newImage.exists()
					|| newImage.lastModified() < Preferences
							.getProfilePhotoLastModified(ctx)) {
				file = Utils.transformImage(image, newImage, width, height);
				file.setLastModified(System.currentTimeMillis());
			} else {
				file = newImage;
			}
		}
		return file;
	}

	private static File getCacheFile(final Context ctx, String pathname) {
		return Files.camouflage(ctx, pathname);
	}

	public static File getMyPhotoOriginal(Context ctx) {
		String photo = Preferences.getProfilePhoto(ctx);
		if (TextUtils.isEmpty(photo)) {
			return null;
		}
		String path = Utils.getDataPath(ctx, Uri.parse(photo));
		if (path == null) {
			return null;
		}
		final File image = new File(path);
		return image;
	}

	/**
	 * Photo thumbnail
	 * 
	 * @param ctx
	 * @return
	 */
	public static File getMyPhotoThumbnail(Context ctx) {
		String photo = Preferences.getProfilePhoto(ctx);
		if (TextUtils.isEmpty(photo)) {
			return null;
		}
		String path = Utils.getDataPath(ctx, Uri.parse(photo));
		if (path == null) {
			return null;
		}
		File newImage = Files.camouflage(ctx, MY_PROFILE_PATH + "thumb.png");
		final File image = new File(path);

		// ensure parent folder
		if (!newImage.exists()) {
			newImage.getParentFile().mkdirs();
		}

		if (!newImage.exists()
				|| newImage.lastModified() < Preferences
						.getProfilePhotoLastModified(ctx)) {
			try {
				newImage = Utils.transformImage(image, newImage, 96, 96);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		newImage.setLastModified(System.currentTimeMillis());
		return newImage;
	}

	public static void deletePeer(Context ctx,
			String peer) {
		File cacheDir = Files.getCacheDir(ctx);
		File p = new File(cacheDir, PEER_PROFILE_PATH + peer);
		deleteAll(p);
		
		File js = new File(cacheDir, PEER_JSON_PATH + peer);
		deleteAll(js);
		
		Preferences.removeStar(ctx, peer);
	}

	public static void deleteAll(File dir) {
		if (dir.isFile()) {
			dir.delete();
			return;
		}
		File[] files = dir.listFiles();
		if (files != null) {
			for (int i = 0; i < files.length; i++) {
				deleteAll(files[i]);
			}
		}
		dir.delete();
	}
}
